﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    //TODO: check if highpass works correctly
    /// <summary>
    /// 
    /// </summary>
    public class Highpass : BaseImageFilter
    {
        protected int m_nWeight = 10;
        protected int m_nZ = 0;

        public Highpass()
            : this(3, 10)
        {
        }

        public Highpass(int _nZ, int _nWeight)
        {
            m_nZ = _nZ;
            m_nWeight = _nWeight; //1 means no weight
        }

        public int Weight
        {
            get { return m_nWeight; }
            set { m_nWeight = value; }
        }

        public int Z
        {
            get { return m_nZ; }
            set { m_nZ = value; }
        }

        /// <summary>
        /// Execute the highpass filter
        /// </summary>
        /// <param name="_bitmap"></param>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            int nSumLeft = 0;
            int nSumRight = 0;
            int nSumTop = 0;
            int nSumBottom = 0;
            int nDivisor = 0;

            int nSum = 0;
            int nHeight = _bitmap.Height;
            int nWidth = _bitmap.Width;
            int nDifference = 0;

            UnsafeBitmap bitmapTemp = new UnsafeBitmap((UnsafeBitmap)_bitmap.Clone());
            UnsafeBitmap bitmap = _bitmap;

            double diff_h = 0.0f;
            double diff_v = 0.0f;

            int y = 0;
            int x = 0;

            int[,] aGray = new int[nWidth, nHeight];

            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    aGray[x, y] = _bitmap.GetGrayPixelValue(x, y);
                }
            }

            Color color = Color.Transparent;
            for (y = 1; y < nHeight - 1; y++)
            {
                for (x = 1; x < nWidth - 1; x++)
                {
                    color = bitmap.GetPixel(x, y);

                    //First optimization step, ready same coordinates only once
                    int nXM1Y = aGray[x - 1, y];        //ColorFunctions.Gray(bitmapTemp.GetGrayPixel(x - 1, y));
                    int nXM1YM1 = aGray[x - 1, y - 1];  //ColorFunctions.Gray(bitmapTemp.GetPixel(x - 1, y - 1));
                    int nXM1YP1 = aGray[x - 1, y + 1];  // ColorFunctions.Gray(bitmapTemp.GetPixel(x - 1, y + 1));
                    int nXP1YP1 = aGray[x + 1, y + 1];  // ColorFunctions.Gray(bitmapTemp.GetPixel(x + 1, y + 1));
                    int nXP1Y = aGray[x + 1, y];        // ColorFunctions.Gray(bitmapTemp.GetPixel(x + 1, y));
                    int nXP1YM1 = aGray[x + 1, y - 1];  // ColorFunctions.Gray(bitmapTemp.GetPixel(x + 1, y - 1));
                    int nXYM1 = aGray[x, y - 1];        // ColorFunctions.Gray(bitmapTemp.GetPixel(x, y - 1));
                    int nXYP1 = aGray[x, y + 1];        // ColorFunctions.Gray(bitmapTemp.GetPixel(x, y + 1));
                    nSumLeft = nXM1Y + nXM1YM1 + nXM1YP1;
                    nSumRight = nXP1Y + nXP1YM1 + nXP1YP1;
                    nSumTop = nXYM1 + nXM1YM1 + nXP1YM1;
                    nSumBottom = nXYP1 + nXM1YP1 + nXP1YP1;
                    //nSumLeft = ColorFunctions.Gray(bitmapTemp.GetPixel(x - 1, y)) + ColorFunctions.Gray(bitmapTemp.GetPixel(x - 1, y - 1)) + ColorFunctions.Gray(bitmapTemp.GetPixel(x - 1, y + 1));
                    //nSumRight = ColorFunctions.Gray(bitmapTemp.GetPixel(x + 1, y)) + ColorFunctions.Gray(bitmapTemp.GetPixel(x + 1, y - 1)) + ColorFunctions.Gray(bitmapTemp.GetPixel(x + 1, y + 1));
                    //nSumTop = ColorFunctions.Gray(bitmapTemp.GetPixel(x, y - 1)) + ColorFunctions.Gray(bitmapTemp.GetPixel(x - 1, y - 1)) + ColorFunctions.Gray(bitmapTemp.GetPixel(x + 1, y - 1));
                    //nSumBottom = ColorFunctions.Gray(bitmapTemp.GetPixel(x, y + 1)) + ColorFunctions.Gray(bitmapTemp.GetPixel(x - 1, y + 1)) + ColorFunctions.Gray(bitmapTemp.GetPixel(x + 1, y + 1));
                    nDifference = Math.Abs(nSumLeft - nSumRight);
                    if (nDifference > 255)
                    {
                        bitmap.SetPixel(x, y, Definitions.White);
                    }
                    else
                    {
                        bitmap.SetPixel(x, y, Color.FromArgb(nDifference, nDifference, nDifference));
                    }
                    nDifference = nSumTop - nSumBottom;
                    if (nDifference < 0) nDifference *= -1;
                    if (nDifference > 255)
                    {
                        bitmap.SetPixel(x, y, Definitions.White);
                    }
                    else
                    {
                        bitmap.SetPixel(x, y, Color.FromArgb(nDifference, nDifference, nDifference));
                    }
                    diff_h = nSumLeft - nSumRight;
                    diff_v = nSumTop - nSumBottom;
                    nDifference = Convert.ToInt32(Math.Sqrt(diff_h * diff_h + diff_v * diff_v));
                    if (nDifference > 255)
                    {
                        bitmap.SetPixel(x, y, Definitions.White);
                    }
                    else
                    {
                        bitmap.SetPixel(x, y, Color.FromArgb(nDifference, nDifference, nDifference));
                    }
                }
            }
            bitmapTemp.Dispose();
            return _bitmap;
        }

        public override object Clone()
        {
            return new Highpass(this.m_nZ, this.m_nWeight);
        }
    }
}
